/*
 * Copyright (C) 2010-2011 sunjumper@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package mfinder.spring;

import java.util.List;
import mfinder.ActionFactory;
import mfinder.ActionInvocation;
import mfinder.MFinderException;
import mfinder.impl.DefaultActionFactory;
import mfinder.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * 提供与springframework集成的ActionFactory。
 */
public class DefaultActionFactoryBean implements FactoryBean<ActionFactory>, InitializingBean,
        DisposableBean {

    /** Logger available to subclasses */
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    /* ActionFactory类 */
    private Class<? extends ActionFactory> actionFactoryClass = null;

    /* Action工厂 */
    private ActionFactory actionFactory;

    /** @see DefaultActionFactory#defaultInterceptorStack */
    private String defaultInterceptorStack = null;

    /** @see DefaultActionFactory#defaultResultType */
    private String defaultResultType = null;

    /** @see DefaultActionFactory#actionInvocationClass */
    private Class<? extends ActionInvocation> actionInvocationClass;

    /** @see DefaultActionFactory#extension */
    private String extension = null;

    /** @see DefaultActionFactory#actionCacheNumber */
    private int actionCacheNumber = -1;

    /* 拦截器的bean名称和类名称的集合 */
    private List<Object> interceptors = null;

    /* 拦截栈的bean名称和类名称的集合 */
    private List<Object> interceptorStacks = null;

    /* 结果类型的bean名称和类名称的集合 */
    private List<Object> resultTypes = null;

    /* Action的bean名称和类名称的集合 */
    private List<Object> actions = null;

    /**
     * 返回ActionFactory。
     * 如果ActionFactory未实例化则抛出异常。
     *
     * @return 不为<code>null</code>)的ActionFactory
     *
     * @throws IllegalStateException 如果ActionFactory未实例化。
     */
    protected final ActionFactory getActionFactory() {
        if (this.actionFactory == null) {
            throw new IllegalStateException("ActionFactory not initialized yet");
        }
        return this.actionFactory;
    }

    /**
     * 初始化ActionFactory。
     *
     * @see #buildActionFactory()
     * @see #afterActionFactoryCreation(mfinder.ActionFactory)
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        logger.info("Creating MFinder ActionFactory");
        this.actionFactory = actionFactoryClass == null
                ? new DefaultActionFactory()
                : actionFactoryClass.newInstance();

        afterActionFactoryCreation(actionFactory);

        this.actionFactory = buildActionFactory();

    }

    /**
     * 在bean工厂关闭时移除ActionFactory中所有关联关系。
     *
     * @throws MFinderException 如果发生错误。
     */
    @Override
    public void destroy() throws MFinderException {
        logger.info("Closing MFinder ActionFactory");
        try {
            beforeActionFactoryDestruction();
        } finally {
            this.actionFactory.clear();
        }
    }

    /**
     * 返回ActionFactory对象，默认为单例状态。
     */
    @Override
    public ActionFactory getObject() {
        return this.actionFactory;
    }

    @Override
    public Class<? extends ActionFactory> getObjectType() {
        return actionFactory == null ? null : actionFactory.getClass();
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    /**
     * 初始化 MFinder ActionFactory。
     *
     * @return 已初始化的ActionFactory。
     *
     * @throws Exception 如果初始化失败。
     */
    protected ActionFactory buildActionFactory() throws Exception {
        logger.info("Building MFinder ActionFactory");
        actionFactory.setDefaultInterceptorStack(defaultInterceptorStack);
        actionFactory.setDefaultResultType(defaultResultType);

        for (Object obj : interceptors) {
            actionFactory.addInterceptors(
                    obj instanceof String
                    ? Class.forName((String) obj)
                    : obj);
        }

        for (Object obj : interceptorStacks) {
            actionFactory.addInterceptorStacks(
                    obj instanceof String
                    ? Class.forName((String) obj)
                    : obj);
        }

        for (Object obj : resultTypes) {
            actionFactory.addResultTypes(
                    obj instanceof String
                    ? Class.forName((String) obj)
                    : obj);
        }
        for (Object obj : actions) {
            actionFactory.addActions(
                    obj instanceof String
                    ? Class.forName((String) obj)
                    : obj);
        }
        return actionFactory;
    }

    /**
     * Hook that allows post-processing after the ActionFactory has been
     * successfully created. The ActionFactory is already available through
     * <code>getActionFactory()</code> at this point.
     * <p>This implementation adds <code>extension</code> to
     * <code>actionFactory</code> if it's instance of <code>DefaultActionFactory</code>.
     *
     * @param actionFactory ActionFactory。
     *
     * @throws Exception in case of initialization failure。
     *
     * @see #getActionFactory()
     */
    protected void afterActionFactoryCreation(ActionFactory actionFactory) throws Exception {
        if (actionFactory instanceof DefaultActionFactory) {
            ((DefaultActionFactory) actionFactory).setActionInvocationClass(actionInvocationClass);
            ((DefaultActionFactory) actionFactory).setExtension(extension);
            if (actionCacheNumber > 0)
                ((DefaultActionFactory) actionFactory).setActionCacheNumber(actionCacheNumber);
        }
    }

    /**
     * Hook that allows shutdown processing before the ActionFactory
     * will be closed. The ActionFactory is still available through
     * <code>getActionFactory()</code> at this point.
     * <p>This implementation is empty.
     *
     * @see #getActionFactory()
     */
    protected void beforeActionFactoryDestruction() {
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////

    /**
     * 返回Action的bean名称和类名称的集合。
     *
     * @return Action的bean名称和类名称的集合。
     */
    public List<Object> getActions() {
        return actions;
    }

    /**
     * 设置Action的bean名称和类名称的集合。
     *
     * @param actions Action的bean名称和类名称的集合。
     */
    public void setActions(List<Object> actions) {
        this.actions = actions;
    }

    /**
     * @deprecated
     *
     * @see #setActionFactoryClass(java.lang.String)
     */
    @Deprecated
    public void setClassName(String className) throws ClassNotFoundException {
        setActionFactoryClass(className);
    }

    /**
     * 设置ActionFactory类名称。
     *
     * @param actionFactoryClass ActionFactory类名称。
     */
    public void setActionFactoryClass(String actionFactoryClass) throws ClassNotFoundException {
        if (!StringUtil.isNull(actionFactoryClass))
            this.actionFactoryClass = (Class<? extends ActionFactory>) Class.forName(actionFactoryClass);
    }

    /**
     * @see ActionFactory#getDefaultInterceptorStack()
     */
    public String getDefaultInterceptorStack() {
        return defaultInterceptorStack;
    }

    /**
     * @see ActionFactory#setDefaultInterceptorStack(java.lang.String)
     */
    public void setDefaultInterceptorStack(String defaultInterceptorStack) {
        this.defaultInterceptorStack = defaultInterceptorStack;
    }

    /**
     * @see ActionFactory#getDefaultResultType()
     */
    public String getDefaultResultType() {
        return defaultResultType;
    }

    /**
     * @see ActionFactory#setDefaultResultType(java.lang.String)
     */
    public void setDefaultResultType(String defaultResultType) {
        this.defaultResultType = defaultResultType;
    }

    /**
     * @see DefaultActionFactory#setActionInvocationClass(java.lang.Class)
     */
    public void setActionInvocationClass(String actionInvocationClass) throws ClassNotFoundException {
        if (!StringUtil.isNull(actionInvocationClass))
            this.actionInvocationClass = (Class<? extends ActionInvocation>) Class.forName(actionInvocationClass);

    }

    /**
     * @see DefaultActionFactory#getExtension()
     */
    public String getExtension() {
        return extension;
    }

    /**
     * @see DefaultActionFactory#setExtension(java.lang.String)
     */
    public void setExtension(String extension) {
        this.extension = extension;
    }

    /**
     * @see DefaultActionFactory#getActionCacheNumber()
     */
    public int getActionCacheNumber() {
        return actionCacheNumber;
    }

    /**
     * @see DefaultActionFactory#setActionCacheNumber(int)
     */
    public void setActionCacheNumber(int actionCacheNumber) {
        this.actionCacheNumber = actionCacheNumber;
    }

    /**
     * 返回拦截栈的bean名称和类名称的集合。
     *
     * @return 拦截栈的bean名称和类名称的集合。
     */
    public List<Object> getInterceptorStacks() {
        return interceptorStacks;
    }

    /**
     * 设置拦截栈的bean名称和类名称的集合。
     *
     * @param interceptorStacks 拦截栈的bean名称和类名称的集合。
     */
    public void setInterceptorStacks(List<Object> interceptorStacks) {
        this.interceptorStacks = interceptorStacks;
    }

    /**
     * 返回拦截器的bean名称和类名称的集合。
     *
     * @return 拦截器的bean名称和类名称的集合。
     */
    public List<Object> getInterceptors() {
        return interceptors;
    }

    /**
     * 设置拦截器的bean名称和类名称的集合。
     *
     * @param interceptors 拦截器的bean名称和类名称的集合。
     */
    public void setInterceptors(List<Object> interceptors) {
        this.interceptors = interceptors;
    }

    /**
     * 返回结果类型的bean名称和类名称的集合。
     *
     * @return 结果类型的bean名称和类名称的集合。
     */
    public List<Object> getResultTypes() {
        return resultTypes;
    }

    /**
     * 设置结果类型的bean名称和类名称的集合。
     *
     * @param resultTypes 结果类型的bean名称和类名称的集合。
     */
    public void setResultTypes(List<Object> resultTypes) {
        this.resultTypes = resultTypes;
    }
}
